package com.xtayfjpk.security.gitblit;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.PrincipalUtil;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.x509.X509V3CertificateGenerator;
import org.junit.Before;
import org.junit.Test;

@SuppressWarnings("deprecation")
public class CertificateTest {
	public static String caStorePath = "D:\\installations\\gitblit-1.6.0\\data\\certs\\caKeyStore.p12";
	public static String caPassword = "gitblit";
	public static String caAlias = "gitblit certificate authority";
	public static String BC = "BC";
	
	@Before
	public void before() throws Exception {
		Security.addProvider(new BouncyCastleProvider());
	}
	
	
	@Test
	public void testGenerator()  throws Exception {
		KeyPair keyPair = newKeyPair();
		X509Certificate caCertificate = (X509Certificate) getCaCertificate();
		
		System.out.println(caCertificate.getIssuerX500Principal());
		System.out.println(keyPair.getClass());
		X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
		certificateGenerator.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
		String name = PrincipalUtil.getIssuerX509Principal(caCertificate).getName();
		System.out.println(name);
		//certificateGenerator.setIssuerDN(new X509Principal(name));
		//certificateGenerator.setIssuerDN(new X509Principal("CN=Gitblit Certificate Authority, OU=Gitblit, O=Gitblit, L=Gitblit, ST=NY, C=US"));
		//根据此限定名来确定颁发者
		certificateGenerator.setIssuerDN(new X509Principal("C=US,ST=NY,L=Gitblit,O=Gitblit,OU=Gitblit,CN=Gitblit Certificate Authority"));
		certificateGenerator.setNotBefore(new Date());
		certificateGenerator.setNotAfter(new Date(System.currentTimeMillis()+ 10 * 24 * 60 * 60 * 1000));
		certificateGenerator.setSubjectDN(new X509Principal("CN=192.168.0.163, OU=Gitblit, O=Gitblit, L=Gitblit, ST=NY, C=US"));
		certificateGenerator.setPublicKey(keyPair.getPublic());
		certificateGenerator.setSignatureAlgorithm("SHA512WithRSA");
		X509Certificate cert = certificateGenerator.generateX509Certificate(getCaPrivateKey(), BC);
		
		//System.out.println(cert);
		
		FileOutputStream fos = new FileOutputStream("H:/163.cer");
		fos.write(cert.getEncoded());
		fos.close();
	}
	
	@Test
	public void testGeneratorBuilder()  throws Exception {
		KeyPair keyPair = newKeyPair();
		X509Certificate caCertificate = (X509Certificate) getCaCertificate();
		
		X500Name webDN = new X500Name("CN=192.168.0.163, OU=Gitblit, O=Gitblit, L=Gitblit, ST=NY, C=US");
		X500Name issuerDN = new X500Name(PrincipalUtil.getIssuerX509Principal(caCertificate).getName());
		X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
				issuerDN,
				BigInteger.valueOf(System.currentTimeMillis()),
				new Date(),
				new Date(System.currentTimeMillis()+ 10 * 24 * 60 * 60 * 1000),
				webDN,
				keyPair.getPublic());
		
		JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
		certBuilder.addExtension(X509Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(keyPair.getPublic()));
		certBuilder.addExtension(X509Extension.basicConstraints, false, new BasicConstraints(false));
		certBuilder.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(caCertificate.getPublicKey()));
		
		// support alternateSubjectNames for SSL certificates
		List<GeneralName> altNames = new ArrayList<GeneralName>();
		String commonName = "192.168.0.163";
			altNames.add(new GeneralName(GeneralName.iPAddress, commonName));
		if (altNames.size() > 0) {
			GeneralNames subjectAltName = new GeneralNames(altNames.toArray(new GeneralName [altNames.size()]));
			certBuilder.addExtension(X509Extension.subjectAlternativeName, false, subjectAltName);
		}
		
		
		ContentSigner caSigner = new JcaContentSignerBuilder("SHA512withRSA").setProvider(BC).build(getCaPrivateKey());
		X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certBuilder.build(caSigner));

		FileOutputStream fos = new FileOutputStream("H:/163.cer");
		fos.write(cert.getEncoded());
		fos.close();
	}
	
	
	
	public KeyStore getCaStore() throws Exception {
		KeyStore caStore = KeyStore.getInstance("pkcs12");
		FileInputStream stream = new FileInputStream(caStorePath);
		caStore.load(stream, caPassword.toCharArray());
		stream.close();
		return caStore;
	}
	
	public Certificate getCaCertificate() throws Exception {
		return getCaStore().getCertificate(caAlias);
	}
	
	public PrivateKey getCaPrivateKey() throws Exception {
		return (PrivateKey) getCaStore().getKey(caAlias, caPassword.toCharArray());
	}
	
	public KeyPair newKeyPair() throws Exception {
		KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
		System.out.println(kpGen.getClass());
		kpGen.initialize(2048, new SecureRandom());
		return kpGen.generateKeyPair();
	}
}
